package fr.esipe.agenda.parser;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import android.text.format.DateUtils;

public class Parser {

    private final static String FORMATIONS_URL = "http://admission.ingenieurs2000.com/netypareo/planning.htm";

    private final static String PLANNING_URL = "http://admission.ingenieurs2000.com/netypareo/script/public/pubPlanning.php?NAV_TYPE_IE=&TYPE_RESSOURCE=63000&MODE=SEMAINE&IS_CONTRAINTE_VISIBLE=1&IS_PORTRAIT=0";

    private final static String PLANING_WEEK_PARM = "&NUM_SEMAINE=";

    private final static String PLANING_ID_PARM = "&CODE_RESSOURCE=";

    private static final Pattern HREF_ID_PATTERN = Pattern.compile("CODE_RESSOURCE=([0-9]+)");

    private static final DateFormat SCHECULE_RANGE_DATE_FORMAT = new SimpleDateFormat("HH'H'mm");

    /**
     * Récupère le planning d'une semaine pour une formation
     * @param formationId l'identifiant de la formation
     * @param year l'année du planning
     * @param weekOfYear la semaine du planning (entre 1 et 52)
     * @return la liste des événements de la semaine
     * @throws MalformedURLException si les données ne peuvent pas être
     *         récupérées
     * @throws IOException si les données ne peuvent pas être récupérées
     */
    public List<Event> parseWeeklyPlanning(String formationId, int year, int weekOfYear) throws MalformedURLException, IOException {

        List<Event> events = new LinkedList<Event>();

        String url = PLANNING_URL + PLANING_ID_PARM + formationId + PLANING_WEEK_PARM + year;
        if (weekOfYear < 10)
            url += 0;
        url += weekOfYear;

        Document document = Jsoup.parse(new URL(url), 6000);

        Elements tableRows = document.select("#planningS tr");

        /**
         * Get schedule ranges
         */

        Elements tableHeads = tableRows.first().select("th:gt(0)");
        Date[] scheduleRanges = new Date[tableHeads.size() + 1];
        for (int i = 0; i < tableHeads.size(); i++) {
            Element tableHead = tableHeads.get(i);
            String tableHeadData = tableHead.text();

            try {
                scheduleRanges[i] = SCHECULE_RANGE_DATE_FORMAT.parse(tableHeadData);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }

        // add the last end date
        long lastDateMs = scheduleRanges[tableHeads.size() - 1].getTime();
        lastDateMs = lastDateMs + DateUtils.MINUTE_IN_MILLIS * 15;
        scheduleRanges[scheduleRanges.length - 1] = new Date(lastDateMs);

        /**
         * Get events
         */

        int i = 1;

        while (i < tableRows.size()) {
            Element tableRow = tableRows.get(i);

            Elements tableColumns = tableRow.select("td");

            int totalScheduleRange = 0;

            int dayOfWeek = (i % 7) + 1;

            int startIndex = 0;

            if (tableColumns.isEmpty() == false) {
                Element tableColumn = tableColumns.get(0);

                String classAttr = tableColumn.attr("class");

                if (classAttr != null && "intLigne".equals(classAttr)) {
                    startIndex = 1;
                }
            }

            for (int j = startIndex; j < tableColumns.size(); j++) {

                Element tableColumn = tableColumns.get(j);

                Event event = new Event();
                event.setFormationId(formationId);

                Elements divs = tableColumn.children();
                for (Element div : divs) {

                    String label = div.text();

                    if (label != null && label.length() > 0)
                        event.addLabel(label);
                }

                String colspan = tableColumn.attr("colspan");

                int colspanValue = (colspan == null) ? 0 : Integer.parseInt(colspan);

                Date startTime = getDate(year, weekOfYear, dayOfWeek, scheduleRanges[totalScheduleRange].getTime());
                event.setStartTime(startTime);

                int newTotalScheduleRange = totalScheduleRange + colspanValue;

                totalScheduleRange = newTotalScheduleRange;

                Date endTime = getDate(year, weekOfYear, dayOfWeek, scheduleRanges[totalScheduleRange].getTime());
                event.setEndTime(endTime);

                if (event.getLabels().size() > 0)
                    events.add(event);
            }

            i++;

        }

        return events;
    }

    public List<Formation> parseFormationList() throws MalformedURLException, IOException {

        List<Formation> formations = new ArrayList<Formation>(18);

        Document document = Jsoup.parse(new URL(FORMATIONS_URL), 6000);

        Elements tableRows = document.select("#cadre tr:gt(0)");

        for (Element tableRow : tableRows) {

            Elements tableColumns = tableRow.select("td");

            String group = null;

            if (tableColumns.isEmpty() == false)
                group = tableColumns.get(0).text();

            for (int i = 1; i < tableColumns.size(); i++) {

                Elements as = tableColumns.get(i).select("a");

                if (as.isEmpty() == false) {

                    Element a = as.get(0);

                    Formation formation = new Formation();

                    formation.setGroup(group);

                    formation.setName(a.text());

                    String href = a.attr("href");
                    if (href != null) {
                        Matcher matcher = HREF_ID_PATTERN.matcher(href);
                        if (matcher.find() && matcher.groupCount() == 1)
                            formation.setId(matcher.group(1));
                    }

                    formations.add(formation);
                }
            }
        }
        return formations;
    }

    private static Date getDate(int year, int weekOfYear, int dayOfWeek, long timeInMs) {

        Calendar calendar = GregorianCalendar.getInstance();

        calendar.setTimeInMillis(0);
        calendar.set(Calendar.YEAR, year);
        calendar.add(Calendar.WEEK_OF_YEAR, weekOfYear - 1);
        calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
        calendar.add(Calendar.MILLISECOND, (int) timeInMs);
        Date date = calendar.getTime();
        // Log.d("API", year + " " + weekOfYear + " " + dayOfWeek + " " +
        // timeInMs + " " + Event.DATE_TIME_FORMAT.format(date));

        return date;
    }

}
